package com.snap.vseries.fragment;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.snap.vseries.AppConfig;
import com.snap.vseries.Constants;
import com.snap.vseries.R;
import com.snap.vseries.analyze.DoubleSigmoid;
import com.snap.vseries.analyze.DoubleSigmoidMulti;
import com.snap.vseries.base.BaseFragment;
import com.snap.vseries.bean.ChannelBean;
import com.snap.vseries.bean.ExpInfo;
import com.snap.vseries.bean.HoleInfo;
import com.snap.vseries.chart.MyMarkerView;
import com.snap.vseries.chart.PLineChart;
import com.snap.vseries.chart.PointLineDataSet;
import com.snap.vseries.ui.widget.ChannelLayout;

import java.util.ArrayList;
import java.util.List;

import butterknife.BindView;

@SuppressLint("ValidFragment")
public class ChartMeltingFragment extends BaseFragment {

    @BindView(R.id.chart_layout)
    LinearLayout chartLayout;
    @BindView(R.id.empty_layout)
    FrameLayout emptyLayout;
    @BindView(R.id.chart)
    PLineChart chart;
    @BindView(R.id.cb_origin)
    CheckBox cbOrigin;
    @BindView(R.id.cb_fit)
    CheckBox cbFit;
    @BindView(R.id.cb_multi)
    CheckBox cbMulti;
    @BindView(R.id.cb_no_slope)
    CheckBox cbNoSlope;
    @BindView(R.id.cb_amplitude)
    CheckBox cbAmplitude;
    @BindView(R.id.debug_view)
    LinearLayout fitStepView;
    @BindView(R.id.ll)
    ChannelLayout ll;
    private ExpInfo experimentInfo;
    private int lastChannelFlag;
    private String[] contents;
    private MyMarkerView markerView;

    public ChartMeltingFragment(ExpInfo experimentInfo) {
        this.experimentInfo = experimentInfo;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        initViews();
        initData();
    }

    @Override
    protected int layoutResId() {
        return R.layout.fragment_chart_melting;
    }

    private void initViews() {

        //截图按钮
      /*  captureBtn = getActivity().findViewById(R.id.capture_btn);
        captureBtn.setVisibility(View.VISIBLE);
        captureBtn.setOnClickListener(v -> {
            List<String> pathList = ApkUtils.getUSBPaths(MoleApplication.get());
            if (pathList == null || pathList.size() == 0) {
                ToastUtils.get().showText("未检测到U盘");
                return;
            }
            MoleExecutor.getInstance().execute(new MoleTask<Boolean>() {
                @Override
                public Boolean runInBackground() {
                    return CaptureUtil.saveImg(chartLayout, experimentInfo.getExperimentName(), experimentInfo.getStartTime(), experimentInfo.getTemplateInfo().getSampleList(), pathList.get(0));
                }

                @Override
                public void onCompleted(Boolean result) {
                    if (result) {
                        ToastUtils.get().showText("截图成功");
                    } else {
                        ToastUtils.get().showText("截图失败");
                    }
                }
            });
        });*/
        //图表整体的一些设置
        chart.setDrawGridBackground(false);
        chart.getDescription().setEnabled(false);
        chart.getLegend().setEnabled(false);
        chart.setDrawBorders(false);
        chart.setMaxVisibleValueCount(0);

        //左右的两根Y轴配置
        chart.getAxisRight().setEnabled(false);
        YAxis yAxis = chart.getAxisLeft();
        yAxis.setEnabled(true);
        yAxis.setDrawAxisLine(true);
        yAxis.setDrawGridLines(true);
        yAxis.setGridColor(0xffe8e9ee);
        yAxis.setTextColor(0xff8d909f);
        yAxis.setTextSize(12f);
        yAxis.setGranularity(0.02f);
        yAxis.setLabelCount(10);

        //X轴配置
        XAxis xAxis = chart.getXAxis();
        xAxis.setEnabled(true);
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setDrawAxisLine(true);
        xAxis.setDrawGridLines(true);
        xAxis.setGridColor(0xffe8e9ee);
        xAxis.setTextColor(0xff8d909f);
        xAxis.setTextSize(12f);
        xAxis.setGranularity(1);
        xAxis.setLabelCount(14);

        //操作相关
        chart.getViewPortHandler().setMinMaxScaleX(1f, 5f);
        chart.getViewPortHandler().setMinMaxScaleY(1f, 5f);
        chart.setTouchEnabled(true);
        chart.setDragEnabled(true);
        chart.setScaleEnabled(true);
        chart.setPinchZoom(true);
        markerView = new MyMarkerView(getContext(), R.layout.custom_marker_view, 1);
        chart.setMarker(markerView);
        chart.setDrawMarkers(true);
        chart.invalidate();
    }

    private void initData() {
        HoleInfo holeInfo = experimentInfo.getHoleInfo();
        if (holeInfo.getChannelData() == null) {
            ((DetailAnalyzeFragment) getParentFragment()).setGroupLlVisibility(View.GONE);
            return;
        }
        contents = new String[]{experimentInfo.getFamName(), experimentInfo.getVicName(), experimentInfo.getRoxName(), experimentInfo.getCy5Name()};
        ll.initView(contents, holeInfo.getChannelJoinFlag());
        List<ILineDataSet> dataSets = new ArrayList<>();
        for (int i = 0; i < AppConfig.TOTAL_HOLE_COUNT * AppConfig.TOTAL_CHANNEL_COUNT; i++) {
            PointLineDataSet dataSet = new PointLineDataSet(new ArrayList<>(), (i + 1) + "");
            dataSets.add(dataSet);
            ChannelBean bean = holeInfo.getChannelData().get(i);
            int whichChannel = i / AppConfig.TOTAL_HOLE_COUNT;
            boolean enable = (holeInfo.getChannelJoinFlag() >> whichChannel & 0x01) == 0x01;
            if (bean != null && bean.getFit() != null && enable) {
                dataSet.setMode(LineDataSet.Mode.LINEAR);//线的样式
                dataSet.setLineWidth(2f);//线宽
                dataSet.setDrawValues(false);
                dataSet.setDrawCircles(false);
                dataSet.setDrawCircleHole(false);
                dataSet.setCircleRadius(2.5f);
                dataSet.setCircleColor(Constants.CHANNEL_DEFAULT_COLORS[i / AppConfig.TOTAL_HOLE_COUNT % AppConfig.TOTAL_CHANNEL_COUNT]);
                dataSet.setColor(Constants.CHANNEL_DEFAULT_COLORS[i / AppConfig.TOTAL_HOLE_COUNT % AppConfig.TOTAL_CHANNEL_COUNT]);
                Bundle b = new Bundle();
                b.putInt("channelIndex", whichChannel + 1);
                b.putInt("holeIndex", i % AppConfig.TOTAL_HOLE_COUNT + 1);
                for (int j = 0; j < bean.getFit().length; j++) {
                    dataSet.addEntry(new Entry(j + 1, bean.getFit()[j], b));
                }
                float ct = bean.getCtValue();
                if (ct > 0) {
                    double[] params = bean.getFitParams();
                    DoubleSigmoidMulti f = new DoubleSigmoidMulti(params);
                    dataSet.addPoint(new Entry(ct, (float) f.value(ct)));
                }

                if (dataSet.getEntryCount() == 1) {
                    dataSet.setDrawCircles(true);
                } else {
                    dataSet.setDrawCircles(false);
                }
            }
        }

        LineData lineData = new LineData(dataSets);
        chart.setData(lineData);

        resetAxis(lineData.getYMax());

        chart.invalidate();
        tryShowLines();

        if (lineData.getEntryCount() > 0) {
            emptyLayout.setVisibility(View.GONE);
            ((DetailAnalyzeFragment) getParentFragment()).setGroupLlVisibility(View.VISIBLE);
        } else {
            ((DetailAnalyzeFragment) getParentFragment()).setGroupLlVisibility(View.GONE);
        }
    }
    private void resetAxis(float yMax) {
        LineData lineData = chart.getLineData();
        XAxis xAxis = chart.getXAxis();
        YAxis yAxis = chart.getAxisLeft();

        //y:0 - setting.lightBase*2.5
        //然后动态调整 x:10的倍数
        //          y:超过base*2.5   maxValue*1.1
        int xMax = lineData.getMaxEntryCountSet().getEntryCount();
        int xRound = (xMax + 9) / 10 * 10;
        xMax = xRound - xMax > 1 ? xRound : xRound + 2;
        xAxis.setAxisMaximum(xMax);
        xAxis.setAxisMinimum(0);

        float yInit = 1.4f;
        if (yMax <= yInit) {
            yMax = yInit;
        } else {
            yMax *= 1.1f;
        }
        yAxis.setAxisMaximum(yMax);
        yAxis.setAxisMinimum(0.9f);
    }

    private void tryShowLines() {
        if (getParentFragment() == null) {
            return;
        }
        Bundle bundle = ((DetailAnalyzeFragment) getParentFragment()).getChooseInfo();
        if (bundle != null) {
            boolean[] bs = bundle.getBooleanArray("check");
            int channelFlag = bundle.getInt("channelFlag");
            setShowLines(bs, channelFlag);
        }
    }

    public void setShowLines(boolean[] bs, int channelFlag) {
        if (chart == null || chart.getData() == null || experimentInfo == null) {
            return;
        }
        chart.post(() -> {
            if (AppConfig.Dynamic.exp_detail_show_fit_step) {
                reset(bs.length);
                if (checkOnly(bs)) {
                    showFitStep(bs);
                    return;
                }
            }
            LineData data = chart.getLineData();
            for (int i = 0; i < bs.length; i++) {
                ILineDataSet lineDataSet = data.getDataSetByIndex(i);
                if (lineDataSet != null) {
                    lineDataSet.setVisible(bs[i]);
                    lineDataSet.setHighlightEnabled(bs[i]);
                }
            }
            if (channelFlag != 0 && channelFlag != lastChannelFlag) {
                float[] maxArray = new float[AppConfig.TOTAL_CHANNEL_COUNT];
                for (int i = 0; i < bs.length; i++) {
                    int whichChannel = i / AppConfig.TOTAL_HOLE_COUNT;
                    if ((channelFlag >> whichChannel & 0x01) != 0x01) {
                        continue;
                    }
                    ILineDataSet lineDataSet = data.getDataSetByIndex(i);
                    if (lineDataSet != null && lineDataSet.getYMax() > maxArray[whichChannel]) {
                        maxArray[whichChannel] = lineDataSet.getYMax();
                    }
                }
                float maxY = 0f;
                for (int i = 0; i < maxArray.length; i++) {
                    if (maxArray[i] > maxY) {
                        maxY = maxArray[i];
                    }
                }
                resetAxis(maxY);
                lastChannelFlag = channelFlag;
            }
            markerView.update(data);
            data.notifyDataChanged();
            chart.notifyDataSetChanged();
            chart.invalidate();
        });
    }

    private void reset(int start) {
        LineData data = chart.getLineData();
        int count = data.getDataSetCount();
        if (count > start) {
            //注意倒序移除
            for (int i = count - 1; i >= start; i--) {
                data.removeDataSet(i);
            }
        }
        cbOrigin.setOnCheckedChangeListener(null);
        cbFit.setOnCheckedChangeListener(null);
        cbMulti.setOnCheckedChangeListener(null);
        cbNoSlope.setOnCheckedChangeListener(null);
        cbAmplitude.setOnCheckedChangeListener(null);
        fitStepView.setVisibility(View.GONE);
    }

    private void showFitStep(boolean[] bs) {
        fitStepView.setVisibility(View.VISIBLE);
        chart.post(() -> {
            LineData data = chart.getLineData();
            int index = 0;
            for (int i = 0; i < bs.length; i++) {
                ILineDataSet lineDataSet = data.getDataSetByIndex(i);
                if (lineDataSet != null) {
                    lineDataSet.setVisible(bs[i]);
                    lineDataSet.setHighlightEnabled(bs[i]);
                }
                if (bs[i]) {
                    index = i;
                }
            }
            addDebugLine(index);

            data.notifyDataChanged();
            float maxY = 0;
            int[] arr = {index, bs.length, bs.length + 1, bs.length + 2, bs.length + 3};
            for (int i = 0; i < arr.length; i++) {
                ILineDataSet d = chart.getData().getDataSetByIndex(arr[i]);
                if (d != null && d.getYMax() > maxY) {
                    maxY = d.getYMax();
                }
            }
            resetAxis(maxY);
            lastChannelFlag = -1;

            chart.notifyDataSetChanged();
            chart.invalidate();
        });
    }

    /**
     * 是否仅选中单个孔
     */
    private boolean checkOnly(boolean[] bs) {
        int counter = 0;
        for (int i = 0; i < bs.length; i++) {
            if (bs[i]) {
                counter++;
                if (counter > 1) {
                    return false;
                }
            }
        }
        return counter == 1;
    }

    private void addDebugLine(int index) {
        cbAmplitude.setChecked(true);
        cbAmplitude.setOnCheckedChangeListener((buttonView, isChecked) -> chart.post(() -> {
            chart.getData().getDataSetByIndex(index).setVisible(isChecked);
            chart.getData().getDataSetByIndex(index).setHighlightEnabled(isChecked);
            chart.getData().notifyDataChanged();
            chart.notifyDataSetChanged();
            chart.invalidate();
        }));
        //原始数据
        int length = addOriginLine(index);
        if (length == 0) {
            return;
        }
        //拟合数据
        double[] p = addFitLine(index, length);
        if (p == null) {
            return;
        }
        //去坡度数据
        addNoSlope(index, length, p);
        //除以基数的倍率数据
        addMulti(index, length, p);
    }

    //橙色实线
    private int addOriginLine(int index) {
        HoleInfo holeInfo = experimentInfo.getHoleInfo();
        cbOrigin.setTextColor(0xffff9800);
        cbOrigin.setChecked(true);
        LineDataSet dataSet = new LineDataSet(new ArrayList<>(), "origin");
        chart.getData().addDataSet(dataSet);

        if (holeInfo.getChannelData() == null || holeInfo.getChannelData().get(index) == null) {
            return 0;
        }
        float[] origins = holeInfo.getChannelData().get(index).getOrigin();
        if (origins != null) {
            dataSet.setMode(LineDataSet.Mode.LINEAR);//线的样式
            dataSet.setLineWidth(2f);//线宽
            dataSet.setDrawValues(false);
            dataSet.setDrawCircles(false);
            dataSet.setColor(0xffff9800);
            for (int j = 0; j < origins.length; j++) {
                dataSet.addEntry(new Entry(j + 1, origins[j] / 1000f));
            }
        }
        cbOrigin.setOnCheckedChangeListener((buttonView, isChecked) -> chart.post(() -> {
            dataSet.setVisible(isChecked);
            dataSet.setHighlightEnabled(isChecked);
            chart.getData().notifyDataChanged();
            chart.notifyDataSetChanged();
            chart.invalidate();
        }));

        return origins == null ? 0 : origins.length;
    }

    //棕色虚线
    private double[] addFitLine(int index, int length) {
        cbFit.setTextColor(0xff795548);
        cbFit.setChecked(true);
        LineDataSet dataSet = new LineDataSet(new ArrayList<>(), "fit");
        chart.getData().addDataSet(dataSet);

        ChannelBean bean = experimentInfo.getHoleInfo().getChannelData().get(index);
        if (bean == null || bean.getFitParams() == null) {
            return null;
        }
        dataSet.setMode(LineDataSet.Mode.LINEAR);//线的样式
        dataSet.setLineWidth(2f);//线宽
        dataSet.enableDashedLine(5f, 15f, 0);
        dataSet.setDrawValues(false);
        dataSet.setDrawCircles(false);
        dataSet.setColor(0xff795548);
        DoubleSigmoid f = new DoubleSigmoid(bean.getFitParams());
        for (int j = 0; j < length; j++) {
            dataSet.addEntry(new Entry(j + 1, (float) f.value(j + 1) / 1000f));
        }
        cbFit.setOnCheckedChangeListener((buttonView, isChecked) -> chart.post(() -> {
            dataSet.setVisible(isChecked);
            dataSet.setHighlightEnabled(isChecked);
            chart.getData().notifyDataChanged();
            chart.notifyDataSetChanged();
            chart.invalidate();
        }));
        return bean.getFitParams();
    }

    //紫色虚线
    private void addNoSlope(int index, int length, double[] params) {
        cbNoSlope.setTextColor(0xff4a148c);
        cbNoSlope.setChecked(true);
        LineDataSet dataSet = new LineDataSet(new ArrayList<>(), "noSlope");
        chart.getData().addDataSet(dataSet);

        dataSet.setMode(LineDataSet.Mode.LINEAR);//线的样式
        dataSet.setLineWidth(1.5f);//线宽
        dataSet.enableDashedLine(5f, 15f, 0);
        dataSet.setDrawValues(false);
        dataSet.setDrawCircles(false);
        dataSet.setColor(0xff4a148c);
        DoubleSigmoid f = new DoubleSigmoid(params);
        for (int j = 0; j < length; j++) {
            float v = (float) f.value(j + 1);
//            v -= params[0];
            v -= params[1] * (j + 1);
            v /= 1000f;
            dataSet.addEntry(new Entry(j + 1, v));
        }
        cbNoSlope.setOnCheckedChangeListener((buttonView, isChecked) -> chart.post(() -> {
            dataSet.setVisible(isChecked);
            dataSet.setHighlightEnabled(isChecked);
            chart.getData().notifyDataChanged();
            chart.notifyDataSetChanged();
            chart.invalidate();
        }));
    }

    //棕色虚线
    private void addMulti(int index, int length, double[] params) {
        cbMulti.setTextColor(0xff795548);
        cbMulti.setChecked(true);
        LineDataSet dataSet = new LineDataSet(new ArrayList<>(), "noBase");
        chart.getData().addDataSet(dataSet);

        dataSet.setMode(LineDataSet.Mode.LINEAR);//线的样式
        dataSet.setLineWidth(2f);//线宽
        dataSet.enableDashedLine(5f, 15f, 0);
        dataSet.setDrawValues(false);
        dataSet.setDrawCircles(false);
        dataSet.setColor(0xff795548);
        DoubleSigmoid f = new DoubleSigmoid(params);
        for (int j = 0; j < length; j++) {
            float v = (float) f.value(j + 1);
            v -= params[1] * (j + 1);
            v /= params[0];
            dataSet.addEntry(new Entry(j + 1, v));
        }
        cbMulti.setOnCheckedChangeListener((buttonView, isChecked) -> chart.post(() -> {
            dataSet.setVisible(isChecked);
            dataSet.setHighlightEnabled(isChecked);
            chart.getData().notifyDataChanged();
            chart.notifyDataSetChanged();
            chart.invalidate();
        }));
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        if (!hidden) {
            if (experimentInfo.getHoleInfo().getChannelData() == null) {
                ((DetailAnalyzeFragment) getParentFragment()).setGroupLlVisibility(View.GONE);
            } else {
                if (chart.getData().getEntryCount() > 0) {
                    ((DetailAnalyzeFragment) getParentFragment()).setGroupLlVisibility(View.VISIBLE);
                } else {
                    ((DetailAnalyzeFragment) getParentFragment()).setGroupLlVisibility(View.GONE);
                }
            }
        }
    }

    public interface OnChangedListener {
        void onChanged(int type);
    }

}